unit NPC_Storage;

interface
uses
AsphyreDef, AsphyreSprite, Weapon_Storage, Classes, SysUtils, StrUtils, TypInfo,
 Constants, Vectors2;

type
  TMovingPart = record
    Pos:TPoint2;
    Direction:single;
    AngleSpeed:single;
    Weaponed:boolean;
    PartWeapon:TWeapon;
    RandomCurrent:single;
    FireCurrent:single;
    ReloadCurrent:single;
    Count:integer;    
    //view
    ImageName:string;
    Firing:boolean;
    Fire:single;
    FiringPos:TPoint2;
    DoAnimate:boolean;
    AnimPos:single;
    AnimStart:integer;
    AnimCount:integer;
    AnimSpeed:single;
    AnimPlayMode:TAnimPlayMode;
    AnimLooped:boolean;
    DoFlag1,DoFlag2:boolean;
    DrawAddAngle:single;
    ScaleX,ScaleY:single;
    DrawFx:cardinal;
  end;

TNPC_Static = class (TPersistent)
private
  FName:string;
  FCreating:boolean;
  FCreateName:string;
  FCreateSpeed:single;
  FAddAngle:single;
  FAccuracy:double;

  FDeathAnimImage:string;
  FDeathAnimStart:integer;
  FDeathAnimSpeed:single;
  FDeathAnimCount:integer;
  FDeathAddAngle:single;
  FAttackAnimation:boolean;
  FMoveAnimCount:integer;
  FMoveAnimSpeed:single;
  FAttackAnimStart:integer;
  FAttackAnimCount:integer;
  FAttackAnimSpeed:single;
  FAttackAnimPos:single;
  FAttackAnimMode:TAnimPlayMode;

  FFleeRad:single;
  FSeeRadius:single;
  FAttackRadius:single;

  FAttackWaitMax:single;
  FAngleSpeed,FSpeed:single;
  FAttackWeapon:boolean;
  FGetExperience:single;
  FWeaponName:string;

  //settoobject
  FMass:single;
  FCollideRadius:integer;
  FMaxHealth:single;
  FScaleX,FScaleY:single;
  FImageName:string;
  FMovingParts:array of TMovingPart;
  FEnemies:TStringList;  
public
  function Load(FileName:string):string;
  procedure SetPropertiesToSprite(Sprite:TPhisicObject);
  procedure AddPart(APart:TMovingPart);
published
  property Name:string read FName write FName;
  property Creating:boolean read FCreating write FCreating;
  property CreateName:string read FCreateName write FCreateName;
  property CreateSpeed:single read FCreateSpeed write FCreateSpeed;
  property AddAngle:single read FAddAngle write FAddAngle;
  property DeathAnimImage:string read FDeathAnimImage write FDeathAnimImage;
  property DeathAnimSpeed:single read FDeathAnimSpeed write FDeathAnimSpeed;
  property DeathAnimCount:integer read FDeathAnimCount write FDeathAnimCount;
  property DeathAddAngle:single read FDeathAddAngle write FDeathAddAngle;
  property DeathAnimStart:integer read FDeathAnimStart write FDeathAnimStart;
  property AttackAnimation:boolean read FAttackAnimation write FAttackAnimation;
  property MoveAnimCount:integer read FMoveAnimCount write FMoveAnimCount;
  property MoveAnimSpeed:single read FMoveAnimSpeed write FMoveAnimSpeed;
  property Speed:single read FSpeed write FSpeed;
  property AngleSpeed:single read FAngleSpeed write FAngleSpeed;
  property GetExperience:single read FGetExperience write FGetExperience;
  property FleeRad:single read FFleeRad write FFleeRad;
  property SeeRadius:single read FSeeRadius write FSeeRadius;
  property Accuracy:double read FAccuracy write FAccuracy;
end;

TNPC_Storage = class
private
  function GetNPC_Static(Index:string):TNPC_Static;
public
  FNPCs:array of TNPC_Static;
  property NPCInfo[Index:string]:TNPC_Static read GetNPC_Static;
  procedure AddFromFile(FileName:string);
end;

function HasNPCStaticProperty(APropertyName: String): Boolean;
function MovingPart(APos:TPoint2; AFiringPos:TPoint2; ADirection:single; AAngleSpeed:real; AWeaponed:boolean;
    AWeapon:string; AImageName:string; ADoAnimate:boolean; AAnimStart:integer;
    AAnimCount:integer; AAnimSpeed:single; AAnimPlayMode:TAnimPlayMode;
    ADrawAddAngle:single; AScaleX:single=1; AScaleY:single=1;
    ADrawFx:cardinal=fxBlend; AAnimLooped: boolean=false; AFiring: boolean=
    false):TMovingPart;
    
implementation
uses
ImpactSprite, Main;

function MovingPart(APos:TPoint2; AFiringPos:TPoint2; ADirection:single; AAngleSpeed:real; AWeaponed:boolean;
    AWeapon:string; AImageName:string; ADoAnimate:boolean; AAnimStart:integer;
    AAnimCount:integer; AAnimSpeed:single; AAnimPlayMode:TAnimPlayMode;
    ADrawAddAngle:single; AScaleX:single=1; AScaleY:single=1;
    ADrawFx:cardinal=fxBlend; AAnimLooped: boolean=false; AFiring: boolean=
    false):TMovingPart;
begin
  Result.Pos:=APos;
  Result.Direction:=ADirection;
  Result.Weaponed:=AWeaponed;
  Result.PartWeapon:=TWeapon.Create;
  Result.PartWeapon.CopyValuesFrom(WeaponStorage.Weapon[AWeapon]);
  Result.ImageName:=AImageName;
  Result.DoAnimate:=ADoAnimate;
  Result.AnimStart:=AAnimStart;
  Result.AnimCount:=AAnimCount;
  Result.AnimSpeed:=AAnimSpeed;
  Result.AnimPlayMode:=AAnimPlayMode;
  Result.DrawAddAngle:=ADrawAddAngle;
  Result.ScaleX:=AScaleX;
  Result.ScaleY:=AScaleY;
  Result.DrawFx:=ADrawFX;
  Result.AnimLooped:=AAnimLooped;
  Result.AngleSpeed:=AAngleSpeed;
  Result.Firing:=AFiring;
  Result.FiringPos:=AFiringPos;
end;

procedure TNPC_Static.SetPropertiesToSprite(Sprite:TPhisicObject);
var
i:integer;
begin
  if Sprite=nil then
  exit;
  if TNPC(Sprite).Enemies=nil then
  TNPC(Sprite).Enemies:=TStringList.Create;
  TNPC(Sprite).Enemies.AddStrings(FEnemies);
  Sprite.Name:=FName;
  Sprite.CollideRadius:=FCollideRadius;
  Sprite.MaxHealth:=FMaxHealth;
  Sprite.ScaleX:=FScaleX;
  Sprite.ScaleY:=FScaleY;
  Sprite.SetAnim(FImageName,0,FMoveAnimCount,FMoveAnimSpeed,true,false,true,pmPingPong);
  Sprite.ChangeCollideAttr(cmRadius,FCollideRadius,FCollideRadius,FMass);
  TNPC(Sprite).StaticConstants:=self;
  for i := 0 to length(FMovingParts)-1 do
  begin
    TNPC(Sprite).AddPart(FMovingParts[i]);
    TNPC(Sprite).Parts[i].PartWeapon:=nil;
    TNPC(Sprite).Parts[i].PartWeapon:=TWeapon.Create;
    TNPC(Sprite).Parts[i].PartWeapon.CopyValuesFrom(FMovingParts[i].PartWeapon);
  end;
end;

function HasNPCStaticProperty(APropertyName: String): Boolean;
var
  PropInfo: PPropInfo;
begin
  PropInfo := GetPropInfo(TNPC_Static, APropertyName);
  Result := PropInfo <> nil;
end;

procedure TNPC_Static.AddPart(APart:TMovingPart);
var
c:integer;
begin
  c:=length(FMovingParts);
  SetLength(FMovingParts,c+1);
  FMovingParts[c]:=APart;
end;

function TNPC_Static.Load(FileName:string):string;
var
StrArr:array[0..20] of string;
S:TStringList;
str,r,d:string;
c1,c2,i:integer;
begin
  S:=TStringList.Create;
  S.LoadFromFile(FileName);
  str:=s.Text;
  S.Free;
  while Pos('//',str)>0 do
  Delete(str,Pos('//',str),PosEx(#13#10,str,Pos('//',str))-Pos('//',str)+2);
  while Pos(#13#10,str)>0 do
  Delete(str,Pos(#13#10,str),2);
  while pos('MaxHealth=',str)>0 do
  begin
    c1:=pos('MaxHealth=',str);
    Delete(str,c1,length('MaxHealth='));
    c2:=PosEx(';',str,c1);
    FMaxHealth:=StrToFloat(Copy(str,c1,c2-c1));
    Delete(str,c1,c2-c1+1);
  end;
  while pos('CollideRadius=',str)>0 do
  begin
    c1:=pos('CollideRadius=',str);
    Delete(str,c1,length('CollideRadius='));
    c2:=PosEx(';',str,c1);
    FCollideRadius:=StrToInt(Copy(str,c1,c2-c1));
    Delete(str,c1,c2-c1+1);
  end;
  while pos('ScaleX=',str)>0 do
  begin
    c1:=pos('ScaleX=',str);
    Delete(str,c1,length('ScaleX='));
    c2:=PosEx(';',str,c1);
    FScaleX:=StrToFloat(Copy(str,c1,c2-c1));
    Delete(str,c1,c2-c1+1);
  end;
  while pos('ScaleY=',str)>0 do
  begin
    c1:=pos('ScaleY=',str);
    Delete(str,c1,length('ScaleY='));
    c2:=PosEx(';',str,c1);
    FScaleY:=StrToFloat(Copy(str,c1,c2-c1));
    Delete(str,c1,c2-c1+1);
  end;
  while pos('ImageName=',str)>0 do
  begin
    c1:=pos('ImageName=',str);
    Delete(str,c1,length('ImageName='));
    c2:=PosEx(';',str,c1);
    FImageName:=Copy(str,c1,c2-c1);
    Delete(str,c1,c2-c1+1);
  end;
  while pos('Mass=',str)>0 do
  begin
    c1:=pos('Mass=',str);
    Delete(str,c1,length('Mass='));
    c2:=PosEx(';',str,c1);
    FMass:=StrToFloat(Copy(str,c1,c2-c1));
    Delete(str,c1,c2-c1+1);
  end;
  while pos('Enemies.Add=',str)>0 do
  begin
    c1:=pos('Enemies.Add=',str);
      Delete(str,c1,length('Enemies.Add='));
    c2:=PosEx(';',str,c1);
    if FEnemies=nil then
    FEnemies:=TStringList.Create;
    FEnemies.Add(Copy(str,c1,c2-c1));
    Delete(str,c1,c2-c1+1);
  end;
  while pos('Movepart.Add=',str)>0 do
  begin
    c1:=pos('Movepart.Add=',str);
    Delete(str,c1,length('Movepart.Add='));
    for i := 0 to 17 do
    begin
      c2:=PosEx(',',str,c1);
      StrArr[i]:=Copy(str,c1,c2-c1);
      Delete(str,c1,c2-c1+1);
    end;
    c2:=PosEx(';',str,c1);
    StrArr[i]:=Copy(str,c1,c2-c1);
    Delete(str,c1,c2-c1+1);    
    AddPart(MovingPart(Point2(StrToFloat(StrArr[0]),StrToFloat(StrArr[1])),
      Point2(StrToFloat(StrArr[2]),StrToFloat(StrArr[3])),
      StrToFloat(StrArr[4]),
      StrToFloat(StrArr[5]),
      StrToBool(StrArr[6]),
      StrArr[7],
      StrArr[8],
      StrToBool(StrArr[9]),
      StrToInt(StrArr[10]),
      StrToInt(StrArr[11]),
      StrToFloat(StrArr[12]),
      pmForward,
      StrToFloat(StrArr[13]),
      StrToFloat(StrArr[14]),
      StrToFloat(StrArr[15]),
      StrToInt64(StrArr[16]),
      StrToBool(StrArr[17]),
      StrToBool(StrArr[18])));
  end;
  while length(str)>0 do
  begin
    d:=copy(str,1,pos('=',str)-1);
    Delete(str,1,pos('=',str));
    c1:=Pos(';',str);
    r:=Copy(str,1,c1-1);
    if HasNPCStaticProperty(d) then
    case PropType(TNPC_Static,d) of
      tkFloat: SetPropValue(Self,d,StrToFloat(r));
      tkString,tkLString,tkWString: SetPropValue(Self,d,r);
      tkInteger: SetPropValue(Self,d,StrToInt(r));
      tkEnumeration:
        if d='AttackAnimation' then
        SetPropValue(Self,d,StrToBool(r));
        else
        if d='AttackAnimMode' then
        begin
          if r='pmPingPong' then
          FAttackAnimMode:=pmPingPong
          else
          if r='pmForward' then
          FAttackAnimMode:=pmForward
          else
          if r='pmBackward' then
          FAttackAnimMode:=pmBackward;
        end;
    end;
    Delete(str,1,c1);
  end;
end;

function TNPC_Storage.GetNPC_Static(Index:string):TNPC_Static;
var
i:integer;
begin
  for i := 0 to length(FNPCs)-1 do
  if Index=FNPCs[i].FName then
  begin
    result:=FNPCs[i];
    break;
  end;
end;

procedure TNPC_Storage.AddFromFile(FileName:string);
var
z:integer;
begin
  z:=length(FNPCs);
  SetLength(FNPCs,z+1);
  FNPCs[z]:=TNPC_Static.Create;
  FNPCs[z].Load(FileName);
end;

initialization
RegisterClass(TNPC_Static);


end.
